package mylib.dir;

/**
 * Created with IntelliJ IDEA.
 * User: 1
 * Date: 20.07.12
 * Time: 17:41
 * To change this template use File | Settings | File Templates.
 */
public class PolyHash {
    private int hash1[];
    private int hash2[];
    private HashInfo info;

    public PolyHash(String s, HashInfo info) {
        this(s.toCharArray(), info);
    }

    public PolyHash(char[] s, HashInfo info) {
        this.info = info;
        hash1 = new int[s.length];
        hash2 = new int[s.length];
        int point1 = info.point1;
        int point2 = info.point2;
        for (int i = 0; i < s.length; ++i) {
            if (i > 0) {
                hash1[i] += hash1[i - 1];
                hash2[i] += hash2[i - 1];
            }
            hash1[i] = (int) ((hash1[i] + (long) (s[i]) * point1) % info.modulo1);
            hash2[i] = (int) ((hash2[i] + (long) (s[i]) * point2) % info.modulo2);
            point1 = (int) ((long) point1 * info.point1 % info.modulo1);
            point2 = (int) ((long) point2 * info.point2 % info.modulo2);
        }
    }

    public long getHash() {
        return getHash(0, hash1.length - 1);
    }

    public long getHash(int l, int r, int shift) {
        long h = getHash(l, r);
        if (shift == 0)
            return h;
        int h1 = (int) (h >> 32);
        int h2 = (int) h;
        h1 = (int) ((long) h1 * info.power1[shift - 1] % info.modulo1);
        h2 = (int) ((long) h2 * info.power2[shift - 1] % info.modulo2);
        return ((long) h1 << 32) + h2;
    }

    /*
    @return  s[l] + s[l + 1] * p + s[l + 2] * p ^ 2 ...
    */
    public long getHash(int l, int r) {
        int h1 = hash1[r] - (l == 0 ? 0 : hash1[l - 1]);
        if (h1 < 0) h1 += info.modulo1;
        if (h1 >= info.modulo1) h1 -= info.modulo1;
        h1 = (int) ((long) h1 * info.inversePower1[l] % info.modulo1);
        int h2 = hash2[r] - (l == 0 ? 0 : hash2[l - 1]);
        if (h2 < 0) h2 += info.modulo2;
        if (h2 >= info.modulo2) h2 -= info.modulo2;
        h2 = (int) ((long) h2 * info.inversePower2[l] % info.modulo2);
        return ((long) h1 << 32) + h2;
    }

}
